import type { Reactive, WatchCallback, WatchOptions } from 'vue'
import { reactive, watch } from 'vue'

/**
 * @file
 * @description
 * @author 黄敏
 * @since 2025-10-09 14:27
 */
export class CreateState<Default extends Record<string, unknown>> {
  /** 内部可写的响应式状态对象 */
  private readonly _state: Reactive<Default>
  /** 外部只读的响应式状态对象，支持Vue的响应式系统 */
  readonly state: Readonly<Default>
  offs: (() => void)[] = []

  constructor(
    private readonly name: string,
    defaults: Default,
    version: number,
    options?: { skipDefaultsCheck?: boolean }
  ) {
    this._state = reactive(_globalState_.storage.get<Default>(name, {
      defaults,
      version,
      options
    }))


    // 创建只读代理，外部无法修改
    // this.state = readonly(this._state) as Readonly<Default>
    //在类型定义它为只读；让ts在运行时检查，不能使用readonly，因为它会在使用type-check命令时，变得很慢。
    this.state = this._state as Readonly<Default>

    // console.log('this._state',this._state)
    // 动态监听所有状态变更，自动同步主进程状态更新
    Object.keys(this._state).forEach(key => {
      const off = _globalState_.storage.onStateUpdated(name, key as keyof Default, data => {
        // @ts-expect-error - 临时 hack
        this._state[key] = data
      })
      if (off) this.offs.push(off)
    })

  }

  /**
   * 监听指定键的状态变化
   * @param key - 要监听的键名
   * @param callback - 状态变化回调函数
   * @param options - watch 选项
   * @returns Vue的watch停止函数
   */
  watch<K extends keyof Default>(
    key: K,
    callback: WatchCallback<Default[K], Default[K] | undefined>,
    options?: WatchOptions
  ) {
    return watch(() => (this._state as Default)[key], callback, options)
  }

  /**
   * 设置状态值
   * @param keyOrData - 要设置的键名或完整的状态对象
   * @param value - 当 keyOrData 为键名时，对应的值
   */
  set = <T extends keyof Default>(keyOrData: T | Partial<Default>, value?: Default[T]) => {
    if (typeof keyOrData === 'object') {
      // 批量更新状态
      _globalState_.storage.set(this.name, keyOrData)
    } else {
      // 更新单个状态值
      _globalState_.storage.set(this.name, value, keyOrData as string)
    }
  }

  destroy () {
    this.offs.forEach(off => off())
  }
}
